using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace AlbumGet
{
    public class SmugMug : IDisposable
    {
        #region Logging
        public delegate void LogEvent(string Message);
        public delegate void ImageEvent(AlbumImage Img);

        public event LogEvent Log;

        protected void OnLog(string Message, params object[] items)
        {
            if (Log != null)
                Log(string.Format(Message, items));
        }
        #endregion

        #region Private Variables
        protected string _API_key = "";
        protected string _BASE_URL = "http://api.SmugMug.com/hack/rest/1.1.1/?APIKey={0}&";
        protected string _SessionID = "";

        protected int RunningDownloads = 0;
        #endregion

        #region Accessors
        public string API_Key
        {
            get { return _API_key; }
            set
            {
                _API_key = value;
                
                // RESET SESSION ID WHEN API KEY IS CHANGED
                _SessionID = "";
            }
        }

        /// <summary>
        /// Gets or sets base URL for REST calls
        /// Format: http://api.SmugMug.com/hack/rest/1.1.1/?APIKey={0}&
        /// </summary>
        public string BaseURL
        {
            get { return string.Format(_BASE_URL, _API_key); }
            set
            {
                _BASE_URL = value;
            }
        }

        public string SessionID
        {
            get
            {
                if (_SessionID.Length == 0)
                {
                    _SessionID = this.GetSessionID();
                }

                return _SessionID;
            }
        }
        #endregion

        #region Constructors
        #endregion

        #region Public Functions
        public SmugMug(string APIKEY)
        {
            this.API_Key = APIKEY;
        }

        public List<int> GetAlbumImages(int AlbumID)
        {
            OnLog("Getting images for album ID {0}", AlbumID);

            XmlTextReader xml2 = new XmlTextReader(
                this.BuildURL("method", "smugmug.images.get",
                    "SessionID", this.SessionID,
                    "AlbumID", AlbumID));

            List<int> res_list = new List<int>();
            while (xml2.Read())
            {
                if (xml2.Name.ToLower() == "image")
                {
                    int res = 0;
                    if (int.TryParse(xml2.GetAttribute("id"), out res))
                    {
                        res_list.Add(res);
                    }
                }
            }

            OnLog("Found {0} images for album ID {1}.", res_list.Count, AlbumID);

            return res_list;
        }

        public string GetImageFilename(string URL, string Directory)
        {
            string res = "";
            int index = URL.LastIndexOf('/');
            if (index > 0)
            {
                string filename = URL.Substring(index + 1);
                if (Directory[Directory.Length - 1] != '/' &&
                    Directory[Directory.Length - 1] != '\\')
                {
                    filename = Directory + "\\" + filename;
                }
                else
                    filename = Directory + filename;

                res = filename;
            }

            return res;
        }

        public AlbumImage GetImageInfo(int ImageID)
        {
            OnLog("Getting image information for ID {0}...", ImageID);

            // REST CALL

            string url = this.BuildURL(
                "method", "smugmug.images.getInfo",
                "SessionID", this.SessionID,
                "ImageID", ImageID);

            XmlTextReader xml = new XmlTextReader(this.BuildURL(
                "method", "smugmug.images.getInfo",
                "SessionID", this.SessionID,
                "ImageID", ImageID));

            AlbumImage res = new AlbumImage();
            while (xml.Read())
            {
                string node_name = xml.Name.ToLower();
                XmlNodeType type = xml.NodeType;

                if (node_name == "originalurl" && type == XmlNodeType.Element)
                {
                    xml.Read();
                    res.OrignalURL = xml.Value;
                }
                else if (node_name == "size" && type == XmlNodeType.Element)
                {
                    xml.Read();
                    int.TryParse(xml.Value, out res.Size);
                }
                else if (node_name == "caption" && type == XmlNodeType.Element)
                {
                    xml.Read();
                    if (xml.NodeType == XmlNodeType.Text)
                        res.Caption = xml.Value;
                }
                else if (node_name == "width" && type == XmlNodeType.Element)
                {
                    xml.Read();
                    if (xml.NodeType == XmlNodeType.Text)
                        int.TryParse(xml.Value, out res.Width);
                }
                else if (node_name == "height" && type == XmlNodeType.Element)
                {
                    xml.Read();
                    if (xml.NodeType == XmlNodeType.Text)
                        int.TryParse(xml.Value, out res.Height);
                }
            }

            OnLog("Got information for image ID {0} {1}", ImageID, res.Caption);

            return res;
        }

        public List<AlbumInfo> GetUserAlbums(string Nickname)
        {
            OnLog("Getting albums for user \"{0}\"...", Nickname);

            // REST CALL

            string url = this.BuildURL(
                "method", "smugmug.albums.get",
                "SessionID", this.SessionID,
                "NickName", Nickname);

            XmlDocument xml = new XmlDocument();
            xml.Load(url);

            List<AlbumInfo> res = new List<AlbumInfo>();

            foreach (XmlNode child0 in xml.ChildNodes)
            {
                if (child0.Name.ToLower() == "rsp" && child0.Attributes["stat"].Value == "ok")
                {
                    foreach (XmlNode AlbumsList in child0.ChildNodes)
                    {
                        if (AlbumsList.Name.ToLower() == "albums")
                        {
                            foreach (XmlNode Album in AlbumsList.ChildNodes)
                            {
                                AlbumInfo thisAlbum = new AlbumInfo();
                                int.TryParse(Album.Attributes["id"].Value, out thisAlbum.AlbumID);

                                foreach (XmlNode Attr in Album.ChildNodes)
                                {
                                    if (Attr.Name.ToLower() == "title")
                                    {
                                        thisAlbum.Title = Attr.InnerText;
                                    }
                                    else if (Attr.Name.ToLower() == "category")
                                    {
                                        int.TryParse(Attr.Attributes["id"].Value, out thisAlbum.CategoryID);
                                        foreach (XmlNode Title in Attr.ChildNodes)
                                        {
                                            if (Title.Name.ToLower() == "title")
                                            {
                                                thisAlbum.Category = Title.InnerText;
                                            }
                                        }
                                    }
                                }

                                res.Add(thisAlbum);
                            }
                        }
                    }
                }
            }

            OnLog("Got albums for {0}", Nickname);

            return res;
        }
        #endregion

        #region Private Functions
        private string BuildURL(params object[] Parameters)
        {
            if (Parameters.Length % 2 != 0)
                throw new Exception("Invalid length of parameters. Parameters must be name then value");

            string res = this.BaseURL;
            for (int a = 0; a < Parameters.Length; a += 2)
            {
                res += Parameters[a] + "=" + Parameters[a + 1] + "&";
            }

            return res;
        }
        private string GetSessionID()
        {
            string res = "";

            OnLog("Logging in and getting session ID...");
            XmlTextReader xml = new XmlTextReader(BuildURL("method", "smugmug.login.anonymously"));

            while (xml.ReadToDescendant("SessionID"))
            {
                xml.Read();
                res = xml.Value;
            }

            OnLog("Logged in (got session ID)");

            return res;
        }
        #endregion

        public class AlbumInfo
        {
            public int AlbumID = 0;
            public string Title;
            public string Category;
            public int CategoryID;
            string SubCategory;

            int SubCategoryID;
        }

        public class AlbumImage
        {
            public int AlbumID;
            public string Caption;
            int Position;
            int Serial;
            public int Size;
            public int Width;
            public int Height;
            string LastUpdated;
            string Keywords;
            public string OrignalURL;
            string LargeURL;
            string MediumURL;
            string SmallURL;
            string ThumbURL;
            string TinyURL;
            string AlbumURL;

            public bool FileDownloaded = false;

            public string SizeString
            {
                get
                {
                    double res = this.Size / (1024.0 * 1024);
                    return res.ToString("0.00") + "MB";
                }
            }

            public string GetImageFilename(string Directory)
            {
                string res = "";
                int index = this.OrignalURL.LastIndexOf('/');
                if (index > 0)
                {
                    string filename = this.OrignalURL.Substring(index + 1);
                    if (Directory[Directory.Length - 1] != '/' &&
                        Directory[Directory.Length - 1] != '\\')
                    {
                        filename = Directory + "\\" + filename;
                    }
                    else
                        filename = Directory + filename;

                    res = filename;
                }

                return res;
            }

            public override string ToString()
            {
                return string.Format(
@"Image ID: {0}
Dimensions: {1}x{2}
Caption: {3}
Original URL: {4}",
                    this.SizeString,
                    this.Width,
                    this.Height,
                    this.Caption,
                    this.OrignalURL);
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
        }

        #endregion
    }
}
